package org.visionlibrary.image.geomtric.lines.compare;

import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import org.visionlibrary.image.geomtric.lines.Lines;
import org.visionlibrary.image.geomtric.lines.compare.model.AbstractSegmentCompare;
import org.visionlibrary.image.geomtric.lines.histogram.CenterOfGravityLineSlope;
import org.visionlibrary.image.geomtric.lines.histogram.LineSlope;
import org.visionlibrary.image.geomtric.model.Point2d;
import org.visionlibrary.image.geomtric.model.Vector2d;
import org.visionlibrary.image.model.Histogram;


/**
 * Klasa realizujaca porownanie dwoch zestawow odcinkow, za pomoca algorytmu
 * opisanego w tresci pracy. Domyslnie wykorzystuje odleglosc euklidesowa jako
 * sposob porownywania dwoch histogramow.
 */
public class SegmentEnergyFunction extends AbstractSegmentCompare {
	//domyslne wartosci dla wag
	protected double weight1 = 20;
	protected double weight2 = 80;

	protected String debugPath = "";

	public SegmentEnergyFunction(double weight1, double weight2) {
		this.weight1 = weight1;
		this.weight2 = weight2;
	}

	@Override
	public double compare(List<Vector2d> linelist1, List<Vector2d> linelist2) {
		double s1 = overallAngleSimilarity(linelist1, linelist2);
		double s2 = overallLineVicinitySimilarity(linelist1, linelist2);
		return (weight1 * s1 + weight2 * s2) / (weight1 + weight2);
	}

	@Override
	public Map<String, Double> compareDetails(List<Vector2d> linelist1,
			List<Vector2d> linelist2) {
		Map<String, Double> result = new LinkedHashMap<String, Double>();
		double s1 = overallAngleSimilarity(linelist1, linelist2);
		double s2 = overallLineVicinitySimilarity(linelist1, linelist2);
		double all = (weight1 * s1 + weight2 * s2) / (weight1 + weight2);

		result.put("overallAngleSimilarity", s1);
		result.put("overallLineVicinitySimilarity", s2);
		result.put("similarity", all);

		return result;
	}

	private double overallAngleSimilarity(List<Vector2d> linelist1,
			List<Vector2d> linelist2) {
		System.out.println("Bez centroidu -- histogram");

		int ma = 5000;
		double maxOverallAngleSimilarity = 0;

		int qiter = 1;
		int qiterStep = 1;
		int qend = 1;

		while (qiter <= qend) {
			Histogram ah1 = (new LineSlope((int) ma / qiter))
					.process(linelist1);
			Histogram nah1 = ah1.getNormalized();

			Histogram ah2 = (new LineSlope((int) ma / qiter))
					.process(linelist2);
			Histogram nah2 = ah2.getNormalized();

			double similarity = similarityMatchAcrossShifts(nah1, nah2);
			if (similarity > maxOverallAngleSimilarity) {
				maxOverallAngleSimilarity = similarity;
			}

			qiter += qiterStep;
		}

		return maxOverallAngleSimilarity;
	}

	private double overallLineVicinitySimilarity(List<Vector2d> linelist1,
			List<Vector2d> linelist2) {
		System.out.println("Z centroidu -- histogram");
		int ma = 5000;
		double maxOverallLineVicinitySimilarity = 0;

		int qiter = 1;
		int qiterStep = 1;
		int qend = 1;

		Point2d c1 = Lines.getWeightedCentroid(linelist1);
		Point2d c2 = Lines.getWeightedCentroid(linelist2);

		while (qiter <= qend) {
			Histogram ahc1 = (new CenterOfGravityLineSlope(c1, (int) ma / qiter))
					.process(linelist1);
			Histogram nahc1 = ahc1.getNormalized();

			Histogram ahc2 = (new CenterOfGravityLineSlope(c2, (int) ma / qiter))
					.process(linelist2);
			Histogram nahc2 = ahc2.getNormalized();

			double similarity = similarityMatchAcrossShifts(nahc1, nahc2);
			if (similarity > maxOverallLineVicinitySimilarity) {
				maxOverallLineVicinitySimilarity = similarity;
			}

			qiter += qiterStep;
		}

		return maxOverallLineVicinitySimilarity;
	}

	private double similarityMatchAcrossShifts(Histogram h1, Histogram h2) {
		double maximumSimilarity = 0;
		int siter = 0;
		int send = h1.getNumBins();

		Histogram sh2 = Histogram.copy(h2);
		while (siter < send) {
			double similarity = Histogram.euclideanDistance(h1, sh2);
			if (similarity > maximumSimilarity) {
				maximumSimilarity = similarity;
			}

			sh2 = Histogram.getShiftedHistogramRightByOne(sh2);
			siter++;
		}

		return maximumSimilarity;
	}
}
